package po

import (
	"GameGo/config"
	"github.com/hajimehoshi/ebiten/v2"
	"github.com/hajimehoshi/ebiten/v2/audio"
	"golang.org/x/image/math/f64"
	"image/color"
	"math"
)

type Player struct {
	PlayerImg     *ebiten.Image
	PlayerX       float64
	PlayerY       float64
	PlayerHP      int
	PlayerMaxHP   int
	PlayerExp     int
	PlayerMaxExp  int
	PlayerLevel   int
	PlayerDamage  int
	ShootCooldown int
	SoundShot     *audio.Player
}

func NewPlayer(playerImg *ebiten.Image, playerX, playerY float64,
	HP, MaxHP int) *Player {
	return &Player{
		PlayerImg:     playerImg,
		PlayerX:       playerX,
		PlayerY:       playerY,
		PlayerHP:      HP,
		PlayerMaxHP:   MaxHP,
		PlayerExp:     0,
		PlayerMaxExp:  config.PlayerExp,
		PlayerLevel:   1,
		PlayerDamage:  config.PlayerDamage,
		ShootCooldown: config.ShootInterval,
	}

}

func (p *Player) PlayerMove() {
	playerW := float64(p.PlayerImg.Bounds().Dx())
	playerH := float64(p.PlayerImg.Bounds().Dy())
	if ebiten.IsKeyPressed(ebiten.KeyLeft) || ebiten.IsKeyPressed(ebiten.KeyA) {
		p.PlayerX -= config.PlayerSpeed
	}
	if ebiten.IsKeyPressed(ebiten.KeyRight) || ebiten.IsKeyPressed(ebiten.KeyD) {
		p.PlayerX += config.PlayerSpeed
	}
	if ebiten.IsKeyPressed(ebiten.KeyUp) || ebiten.IsKeyPressed(ebiten.KeyW) {
		p.PlayerY -= config.PlayerSpeed
	}
	if ebiten.IsKeyPressed(ebiten.KeyDown) || ebiten.IsKeyPressed(ebiten.KeyS) {
		p.PlayerY += config.PlayerSpeed
	}

	// 限制不能出边界
	if p.PlayerX < 0 {
		p.PlayerX = 0
	}
	if p.PlayerX > config.ScreenXSize-float64(playerW) {
		p.PlayerX = config.ScreenXSize - float64(playerW)
	}
	if p.PlayerY < 40 {
		p.PlayerY = 40
	}
	if p.PlayerY > config.ScreenYSize-float64(playerH) {
		p.PlayerY = config.ScreenYSize - float64(playerH)
	}

}

func (p *Player) PlayerShot(Bullets *[]Bullet) {
	//&& ebiten.IsKeyPressed(ebiten.KeySpace)
	playerW := float64(p.PlayerImg.Bounds().Dx())
	playerH := float64(p.PlayerImg.Bounds().Dy())
	if p.ShootCooldown == 0 {
		bullet := Bullet{
			BulletType:     PlayerBullet,
			BulletMoveType: Linear,
			BulletSpeed:    6.0,
			Dir:            DirFromAngle(90), // 向上
			Damage:         p.PlayerDamage,
			Life:           180,
		}
		switch p.PlayerLevel {
		case 1:
			bullet.Scale = 1
			bullet.Position = f64.Vec2{p.PlayerX, p.PlayerY - 10}
			*Bullets = append(*Bullets, bullet)
		case 2:
			bullet.Scale = 0.8
			bullet.Position = f64.Vec2{p.PlayerX + 25, p.PlayerY - 10}
			*Bullets = append(*Bullets, bullet)
			bullet.Position = f64.Vec2{p.PlayerX - 15, p.PlayerY - 10}
			*Bullets = append(*Bullets, bullet)
		case 3:
			bullet.Scale = 1
			bullet.Position = f64.Vec2{p.PlayerX, p.PlayerY - 10}
			*Bullets = append(*Bullets, bullet)
			bullet.Scale = 0.8
			x, y := rotate(f64.Vec2{playerW / 2, playerH / 2}, 30)
			bullet.Position = f64.Vec2{p.PlayerX + 25 - x, p.PlayerY - 20 + y}
			bullet.Dir = DirFromAngle(60)
			*Bullets = append(*Bullets, bullet)
			//x, y = rotate(f64.Vec2{playerW / 2, playerH / 2}, -30)
			bullet.Position = f64.Vec2{p.PlayerX - 15 - y, p.PlayerY - 5 - x}
			bullet.Dir = DirFromAngle(120)
			*Bullets = append(*Bullets, bullet)
		case 4:
			bullet.Scale = 1
			bullet.BulletMoveType = Homing
			bullet.Position = f64.Vec2{p.PlayerX, p.PlayerY - 10}
			*Bullets = append(*Bullets, bullet)
		}
		_ = p.SoundShot.Rewind()
		p.SoundShot.Play()
		p.ShootCooldown = config.ShootInterval
	}
	if p.ShootCooldown > 0 {
		p.ShootCooldown--
	}
}

func (p *Player) DrawPlayerHPBar(screen *ebiten.Image) {
	barWidth := float64(config.ScreenXSize)
	barHeight := 20.0
	if p.PlayerMaxHP <= 0 {
		return // 防止除0
	}
	// 比例
	rate := float64(p.PlayerHP) / float64(p.PlayerMaxHP)
	if rate < 0 {
		rate = 0
	}
	if rate > 1 {
		rate = 1
	}
	width := int(barWidth * rate)
	if width <= 0 {
		width = 1 // 至少画出一个像素
	}

	bg := ebiten.NewImage(int(barWidth), int(barHeight))
	bg.Fill(color.RGBA{50, 50, 50, 255})
	opt := &ebiten.DrawImageOptions{}
	opt.GeoM.Translate(0, 0)
	screen.DrawImage(bg, opt)

	// 血量条
	fg := ebiten.NewImage(width, int(barHeight))
	fg.Fill(color.RGBA{0, 255, 0, 255})
	opt2 := &ebiten.DrawImageOptions{}
	opt2.GeoM.Translate(0, 0)
	screen.DrawImage(fg, opt2)
}

func (p *Player) PlayerLevelUp(exp int) {
	if p.PlayerLevel == config.PlayerMaxLevel {
		p.PlayerExp = p.PlayerMaxExp
		return
	}
	p.PlayerExp += exp
	if p.PlayerExp >= p.PlayerMaxExp {
		p.PlayerExp -= p.PlayerMaxExp
		p.PlayerLevel++
		p.PlayerHP = config.PlayerHP * p.PlayerLevel
		p.PlayerMaxHP = config.PlayerHP * p.PlayerLevel
		p.PlayerMaxExp = ExpForLevel(p.PlayerLevel)
		if p.PlayerLevel%3 != 0 {
			return
		}
		p.PlayerDamage += 2

	}
}

func ExpForLevel(level int) int {
	base := config.PlayerExp
	expFactor := 1.5
	return int(float64(base) * math.Pow(float64(level), expFactor))
}

func DirFromAngle(angleDeg float64) f64.Vec2 {
	rad := angleDeg * math.Pi / 180
	return f64.Vec2{math.Cos(rad), math.Sin(rad)}
}
func rotate(v f64.Vec2, angleDeg float64) (x, y float64) {
	angleRad := angleDeg * math.Pi / 180
	sin, cos := math.Sin(angleRad), math.Cos(angleRad)
	X := v[0]*cos - v[1]*sin
	Y := v[0]*sin + v[1]*cos
	x = math.Abs(X) - math.Abs(v[0])
	y = math.Abs(Y) - math.Abs(v[1])
	return
}
